home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dc1 / lex.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  28KB  |  1,379 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  LEX.C
  9.  */
  10.  
  11. /*
  12. **      $Filename: lex.c $
  13. **      $Author: dice $
  14. **      $Revision: 30.326 $
  15. **      $Date: 1995/12/24 06:09:42 $
  16. **      $Log: lex.c,v $
  17.  * Revision 30.326  1995/12/24  06:09:42  dice
  18.  * .
  19.  *
  20.  * Revision 30.156  1995/01/11  05:04:48  dice
  21.  * MINIDICE2 additions - check for input file too large (disabled, not
  22.  * in MINIDICE release)
  23.  *
  24.  * Revision 30.5  1994/06/13  18:37:31  dice
  25.  * .
  26.  *
  27.  * Revision 30.0  1994/06/10  18:04:52  dice
  28.  * .
  29.  *
  30.  * Revision 1.5  1994/04/15  21:15:00  jtoebes
  31.  * Correct dicecache compile problems.
  32.  * Also fixed warning for hex constants in strings gobbling up characters.
  33.  *
  34.  * Revision 1.4  1993/11/14  17:22:10  jtoebes
  35.  * Eliminate reference to lex.h (empty include file).
  36.  *
  37.  * Revision 1.3  1993/09/12  17:16:42  jtoebes
  38.  * Fixed BUG00120 - \x does not allow a single hex character.
  39.  * Changed the parsing so that it is more in line with ANSI.  \x will
  40.  * parse as many characters as are hex.  also fixed the octal parsing code.
  41.  *
  42.  * Revision 1.2  1993/09/06  10:15:48  jtoebes
  43.  * Fixed BUG01098 - Stack overflow with blank lines causing recursion.
  44.  *
  45. **/
  46.  
  47. #include "defs.h"
  48. #ifdef _DCC
  49. #include <lib/misc.h>    /*  get _parseargs1() & 2   */
  50. #include <ioctl.h>
  51. #include <clib/dicecache_protos.h>
  52. #endif
  53.  
  54. Prototype void InitLex(void);
  55.  
  56. Prototype short LexSimpleToken(void);
  57. Prototype short LexLineFeed(void);
  58. Prototype short LexWhiteSpace(void);
  59. Prototype short LexTLex(void);
  60. Prototype short LexSymbol(void);
  61. Prototype short LexInteger(void);
  62. Prototype short LexDecimal(void);
  63. Prototype short LexCharConst(void);
  64. Prototype short LexString(void);
  65. Prototype short LexToken(void);
  66.  
  67. /*Prototype short LexSymbolRef(short, long);*/
  68. Prototype short LexOctal(ubyte, long);
  69. Prototype short LexHex(ubyte, long);
  70. Prototype short LexFloating(long, long);
  71.  
  72. Prototype void PushLexFile(char *, short, long, long);
  73. Prototype short PopLexFile(void);
  74.  
  75. Prototype int SpecialChar(long *);
  76. Prototype long CharToNibble(short);
  77. Prototype short SkipToken(short, short);
  78. Prototype char *TokenToStr(short);
  79. Prototype long    FindLexFileLine(long, char **, long *, long *);
  80. Prototype short FindLexCharAt(long);
  81.  
  82. Prototype long      LexIntConst;
  83. Prototype char      *LexStrConst;   /*  also flt constant   */
  84. Prototype long      LexStrLen;
  85. Prototype Symbol  *LexSym;
  86. Prototype void      *LexData;
  87. Prototype char      LexHackColon;
  88. Prototype char      LexUnsigned;
  89.  
  90. Prototype char FileName[128];
  91. Prototype char SymbolSpace[256];
  92. Prototype long Depth;
  93. Prototype short ErrorInFileValid;
  94.  
  95. Prototype   long    LexCacheHits;
  96. Prototype   long    LexCacheMisses;
  97. Prototype LexFileNode *LFBase;
  98.  
  99.  
  100. Prototype short (*LexDispatch[256])(void);
  101.  
  102.  
  103. LexFileNode *LFBase;
  104.  
  105. long    LexIntConst;
  106. char    *LexStrConst;    /*  also flt constant    */
  107. long    LexStrLen;
  108. Symbol    *LexSym;
  109. void    *LexData;
  110. char    LexHackColon;
  111. char    LexUnsigned;
  112.  
  113. char FileName[128];
  114. char SymbolSpace[256];
  115. long Depth;
  116.  
  117. long    LexCacheHits;
  118. long    LexCacheMisses;
  119.  
  120. #ifdef NOTDEF
  121. xSymbol  *LexSymRefSym[256];
  122. xshort     LexSymRefIdx;
  123. #endif
  124.  
  125. short    ErrorInFileValid;
  126.  
  127. #define TLF     1
  128. #define TWHITE     2
  129. #define TLEX     3
  130. #define TALPHA     4
  131. #define TZERO     5
  132. #define TNUM     6
  133. #define TCHARC     7
  134. #define TSTRC     8
  135. #define TTOKEN     9
  136. #define TALPHX  10
  137.  
  138. static const char TokenType[256] = {
  139. /*00*/    0,    0,    0,    0,    0,    0,    0,    0,
  140.     0,    TWHITE, TLF,    0,    TWHITE, TWHITE, 0,    0,
  141. /*10*/    0,    0,    0,    0,    0,    0,    0,    0,
  142.     0,    0,    0,    0,    0,    0,    0,    0,
  143. /*20*/    TWHITE, 0,    TSTRC,    0,    0,    0,    0,    TCHARC,
  144.     0,    0,    0,    0,    0,    0,    0,    0,
  145. /*30*/    TZERO,    TNUM,    TNUM,    TNUM,    TNUM,    TNUM,    TNUM,    TNUM,
  146.     TNUM,    TNUM,    0,    0,    0,    0,    0,    0,
  147. /*40*/    0     , TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHA,
  148.     TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
  149. /*50*/    TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
  150.     TALPHA, TALPHA, TALPHA, 0,    0,    0,    0,    TALPHA,
  151. /*60*/    0     , TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHX, TALPHA,
  152.     TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
  153. /*70*/    TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA, TALPHA,
  154.     TALPHA, TALPHA, TALPHA, 0,    0,    0,    0,    0,
  155. /*80*/    TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN, TTOKEN
  156. };
  157.  
  158. /*short LexDispatch*/
  159. short (*LexDispatch[256])(void);
  160.  
  161. short (*LexFuncTable[])(void) = {
  162.     LexSimpleToken,
  163.     LexLineFeed,
  164.     LexWhiteSpace,
  165.     LexTLex,
  166.     LexSymbol,
  167.     LexInteger,
  168.     LexDecimal,
  169.     LexCharConst,
  170.     LexString,
  171.     LexToken,
  172.     LexSymbol
  173. };
  174.  
  175. void
  176. InitLex(void)
  177. {
  178.     short i;
  179.  
  180.     Assert(1);    /* filler to avoid gnu compiler warnings */
  181.  
  182.     {
  183.     char *ss = SymbolSpace;
  184.  
  185.     for (i = 'a'; i <= 'z'; ++i)
  186.         ss[i] = 1;
  187.     for (i = 'A'; i <= 'Z'; ++i)
  188.         ss[i] = 1;
  189.     for (i = '0'; i <= '9'; ++i)
  190.         ss[i] = 1;
  191.     ss['_'] = 1;
  192.     }
  193.     for (i = 0; i < 256; ++i)
  194.     LexDispatch[i] = LexFuncTable[(short)TokenType[i]];
  195. }
  196.  
  197.  
  198. /*
  199.  *  Lexical file push/pop
  200.  */
  201.  
  202. void
  203. PushLexFile(char *name, short nameLen, long begPos, long bytes)
  204. {
  205.     LexFileNode *lf = zalloc(sizeof(LexFileNode) + nameLen + 1);
  206.  
  207.     if (bytes == -2) {
  208.     lf->lf_FileName = "";
  209.     lf->lf_Fi = (FILE *)name;
  210.     } else {
  211.     lf->lf_FileName = (char *)(lf + 1);
  212.     movmem(name, lf->lf_FileName, nameLen);
  213.     lf->lf_FileName[nameLen] = 0;
  214.  
  215.     if ((lf->lf_Fi = fopen(lf->lf_FileName, "r")) == NULL)
  216.         zerror(EFATAL_CANT_OPEN_FILE, lf->lf_FileName);
  217.     }
  218.  
  219.     if (bytes < 0) {
  220.     fseek(lf->lf_Fi, 0L, 2);
  221.     if ((bytes = ftell(lf->lf_Fi)) < 0)
  222.         zerror(EFATAL_INPUT_NOT_SEEKABLE);
  223.     fseek(lf->lf_Fi, begPos, 0);
  224.     } else {
  225.     fseek(lf->lf_Fi, begPos, 0);
  226.     }
  227. #ifdef MINIDICE2
  228.     if (bytes > 65530) {
  229.         zerror(EFATAL_INPUT_TOO_LARGE, bytes);
  230.     }
  231. #endif
  232. #ifdef _DCC
  233.     /*
  234.      * HACK!  we should really add an IODOM_CACHE field and make ioctl()
  235.      *        return it for cached files.
  236.      */
  237.     if (ioctl(fileno(lf->lf_Fi), IOC_DOMAIN, NULL) != IODOM_AMIGADOS) {
  238.     /*
  239.      *  DICECACHE support - directly reference the cache.  Note that
  240.      *  we cannot close the file handle without invalidating our
  241.      *  cache entry and, since we reference pointers into the buffer,
  242.      *  that means we cannot close any handles until the program is
  243.      *  done.
  244.      */
  245.  
  246.         struct {
  247.             void *cfh_Cn;    // dicecache.library descriptor
  248.             long  cfh_Size;
  249.             long  cfh_Pos;
  250.         } *cfh = (void *)ioctl(fileno(lf->lf_Fi), IOC_GETDESC, NULL);
  251.  
  252.     lf->lf_Buf = DiceCacheSeek(cfh->cfh_Cn, begPos, &lf->lf_Size);
  253.     lf->lf_Size = bytes;    /* XXX check against lf_Size    */
  254.     /*fprintf(stderr, "PUSH-CACHED %08lx %d\n", lf->lf_Buf, lf->lf_Size);*/
  255.     } else
  256. #endif
  257.     {
  258.     /*fprintf(stderr, "PUSH-UNCACHED %d\n", bytes);*/
  259.     if ((lf->lf_Buf = malloc(bytes + 4)) != NULL) {
  260.         fread(lf->lf_Buf, bytes, 1, lf->lf_Fi);
  261.         clrmem(lf->lf_Buf + bytes, 4);
  262.         lf->lf_Size = bytes;
  263.     } else {
  264.         NoMem();
  265.     }
  266.     }
  267.  
  268.     lf->lf_Next = LFBase;
  269.     lf->lf_Index= 0;
  270.     lf->lf_BaseIndex = 0;
  271.     LFBase = lf;
  272. }
  273.  
  274. short
  275. PopLexFile(void)
  276. {
  277.  
  278.     /*fprintf(stderr, "POPLEX %d\n", LFBase->lf_Index);*/
  279.  
  280.     if (LFBase) {
  281.     LexFileNode *lf;
  282.  
  283.     if ((lf = LFBase->lf_Next) != NULL) {
  284.         LFBase = lf;
  285.         return(1);
  286.     }
  287.     /*
  288.      *  don't clear out last LFBase because lexical routines presume
  289.      *  one exists!
  290.      */
  291.     }
  292.     return(0);
  293. }
  294.  
  295. short
  296. LexToken(void)
  297. {
  298.     long i = LFBase->lf_Index;
  299.     ubyte *ptr = LFBase->lf_Buf + i;
  300.  
  301.     LFBase->lf_Index = i + 2;
  302.  
  303. #ifdef NOTDEF
  304. x    if (*ptr == TokCppRef_Byte) {
  305. x     return(LexSymbolRef(ptr[1], i + 2));
  306. x    } else
  307. #endif
  308.     {
  309.     return((ptr[0] << 12) | ptr[1]);
  310.     }
  311. }
  312.  
  313. short
  314. LexLineFeed(void)
  315. {
  316.     long i = LFBase->lf_Index;
  317.     char *ptr = LFBase->lf_Buf + i;
  318.     char *base;
  319.  
  320.     do {
  321.     base = ptr;
  322.  
  323.         while (*ptr == '\n')    /*  optimize \n\n\n...  */
  324.             ++ptr;
  325.         while (*ptr == '#') {   /*  # line "file" depth */
  326.             ++ptr;
  327.             while (*ptr == ' ' || *ptr == 9)
  328.                 ++ptr;
  329.  
  330.             /*
  331.              *  Ignore # line constructs, handle others
  332.              */
  333.  
  334.             if (*ptr < '0' || *ptr > '9') {
  335.                 if (strncmp(ptr, "pragma", 6) == 0) {
  336.                     ptr += 6;
  337.                     while (*ptr == ' ' || *ptr == 9)
  338.                         ++ptr;
  339. #ifdef REGISTERED
  340.                     if (strncmp(ptr, "libcall", 7) == 0) {
  341.                         ProcessLibCallPragma(ptr + 7, 0);
  342.                     } else if (strncmp(ptr, "syscall", 7) == 0) {
  343.                         ProcessLibCallPragma(ptr + 7, 1);
  344.                     } else
  345. #endif
  346.                     if (strncmp(ptr, "DCCOPTS", 7) == 0) {
  347.                         /*
  348.                          *  Process #pragma DCCOPTS.  Note that
  349.                          *  associated memory is permanent since some options
  350.                          *  refer directly to the parsed string.
  351.                          */
  352. #ifdef _DCC
  353.                         char *p2 = ptr;
  354.                         short len;
  355.                         short ac;
  356.                         char **av;
  357.  
  358.                         while (*p2 && *p2 != '\n')
  359.                             ++p2;
  360.                         len = p2 - ptr;
  361.                         movmem(ptr, p2 = zalloc(len + 1), len);
  362.                         if (ac = _parseargs1(p2 + 7, len - 7)) {
  363.                             av = zalloc((ac + 2) * 4);
  364.                             _parseargs2(p2 + 7, av + 1, ac);
  365.                             ++ac;
  366.                             ParseOpts(ac, av, 0);
  367.                         }
  368. #endif
  369.                     }
  370.                 } else if (strncmp(ptr, "precomp", 7) == 0) {
  371.                     long begPos;
  372.                     long bytes;
  373.                     char *name;
  374.                     short nameLen;
  375.  
  376.                     for (; *ptr && *ptr != ' '; ++ptr)
  377.                         ;
  378.                     begPos = atoi(ptr);
  379.                     for (ptr = ptr + 1; *ptr && *ptr != ' '; ++ptr)
  380.                         ;
  381.                     bytes = atoi(ptr);
  382.                     while (*ptr && *ptr != '\"')
  383.                         ++ptr;
  384.                     name = ptr + 1;
  385.                     for (ptr = ptr + 1; *ptr && *ptr != '\"'; ++ptr)
  386.                         ;
  387.                     nameLen = ptr - name;
  388.                     while (*ptr && *ptr != '\n')
  389.                         ++ptr;
  390.                     LFBase->lf_Index = ptr - LFBase->lf_Buf + 1;
  391.                     PushLexFile(name, nameLen, begPos, bytes);
  392.                     return(GetToken());
  393.                 } else if (strncmp(ptr, "debug", 5) == 0) {
  394.                     DDebug = atoi(ptr + 5);
  395.                 } else {
  396.                     /* ignore... # line (parsed for error conditions only) */
  397.                 }
  398.             }
  399.             while (*ptr && *ptr != '\n')
  400.                 ++ptr;
  401.             while (*ptr == '\n')
  402.                 ++ptr;
  403.         }
  404.         while (*ptr == ' ' || *ptr == '\t') /* optimization */
  405.             ++ptr;
  406.         LFBase->lf_Index = ptr - LFBase->lf_Buf;
  407.     } while (base != ptr);
  408.     return(GetToken());
  409. }
  410.  
  411. short
  412. LexWhiteSpace(void)
  413. {
  414.     const ubyte *tt = TokenType;
  415.     const ubyte *ptr = LFBase->lf_Buf + LFBase->lf_Index;
  416.  
  417.     while (tt[*ptr] == TWHITE)
  418.     ++ptr;
  419.     LFBase->lf_Index = (char *)ptr - (char *)LFBase->lf_Buf;
  420.     return(GetToken());
  421. }
  422.  
  423. short
  424. LexTLex(void)
  425. {
  426.     return(GetToken());
  427. }
  428.  
  429.  
  430. /*
  431.  *  Lexical Symbol.  Symbol-init has already predefined most symbols
  432.  */
  433.  
  434. short
  435. LexSymbol(void)
  436. {
  437.     const ubyte *base = LFBase->lf_Buf + LFBase->lf_Index;
  438.     const ubyte *ptr = base;
  439.  
  440.     {
  441.     ubyte *ss = SymbolSpace;
  442.  
  443.     while (ss[*ptr])
  444.         ++ptr;
  445.     }
  446.     LexSym = MakeSymbol(base, ptr - base, TokId, NULL);
  447.     LexData= LexSym->Data;
  448.  
  449. #ifdef NOTDEF
  450. x    LexSymRefSym[LexSymRefIdx] = LexSym;
  451. x    LexSymRefIdx = (LexSymRefIdx + 1) & 0xFF;
  452. #endif
  453.  
  454.     {
  455.     const ubyte *tt = TokenType;
  456.  
  457.     while (tt[*ptr] == TWHITE)
  458.         ++ptr;
  459.     }
  460.     LFBase->lf_Index = (char *)ptr - (char *)LFBase->lf_Buf;
  461.  
  462.     if (*ptr != ':') {
  463.     LexHackColon = 0;
  464.     return(LexSym->LexId);
  465.     } else {
  466.     LexHackColon = 1;
  467.  
  468.     switch(LexSym->LexId) {
  469.     case TokVarId:
  470.     case TokCase:
  471.     case TokDefault:
  472.     case TokEnumConst:
  473.         return(LexSym->LexId);
  474.     default:
  475.         return(TokId);
  476.     }
  477.     }
  478. }
  479.  
  480. #ifdef NOTDEF
  481. x
  482. x/*
  483. x *  precompiled header support from DCPP, DCPP recognizes a previously
  484. x *  defined symbol and gives a simple reference index with which we
  485. x *  can look up the symbol instantly.
  486. x */
  487. x
  488. xshort
  489. xLexSymbolRef(relId, i)
  490. xshort relId;
  491. xlong i;
  492. x{
  493. x    relId = (LexSymRefIdx - relId) & 0xFF;
  494. x    LexSym = LexSymRefSym[relId];
  495. x
  496. x#ifdef NOTDEF
  497. x    LexSym = MakeSymbol(LexSymRefPtr[relId], LexSymRefLen[relId], TokId, NULL);
  498. x#endif
  499. x    LexData = LexSym->Data;
  500. x
  501. x    if (LexBuf[i] == ':') {
  502. x     LexHackColon = 1;
  503. x
  504. x     switch(LexSym->LexId) {
  505. x     case TokVarId:
  506. x     case TokCase:
  507. x     case TokDefault:
  508. x     case TokEnumConst:
  509. x         return(LexSym->LexId);
  510. x     default:
  511. x         return(TokId);
  512. x     }
  513. x    } else {
  514. x     LexHackColon = 0;
  515. x     return(LexSym->LexId);
  516. x    }
  517. x}
  518. x
  519. #endif
  520.  
  521. /*
  522.  *  Hex or Octal
  523.  */
  524.  
  525. short
  526. LexInteger(void)
  527. {
  528.     long i = LFBase->lf_Index + 1;
  529.     ubyte c = LFBase->lf_Buf[i++];        /*    second char */
  530.  
  531.     if (c == 'x' || c == 'X')
  532.     return(LexHex(LFBase->lf_Buf[i], i + 1));
  533.     return(LexOctal(c, i));
  534. }
  535.  
  536. short
  537. LexOctal(ubyte c, long i)
  538. {
  539.     long v = 0;
  540.     long b = i - 2;    /*  if flt  */
  541.     char *lexBuf = LFBase->lf_Buf;
  542.  
  543.     LexUnsigned = 0;
  544.     while (c >= '0' && c <= '7') {
  545.     v = (v << 3) + (c - '0');
  546.     c = lexBuf[i++];
  547.     }
  548.     if (v & 0x80000000)
  549.     LexUnsigned = 1;
  550.  
  551.     while (c == 'L' || c == 'l' || c == 'U' || c == 'u') {
  552.     if (c == 'u' || c == 'U')
  553.         LexUnsigned = 1;
  554.     c = lexBuf[i++];
  555.     }
  556.     if (c == '.' || c == 'e' || c == 'E')
  557.     return(LexFloating(b, i));
  558.  
  559.     LFBase->lf_Index = i - 1;
  560.     LexIntConst = v;
  561.     return(TokIntConst);
  562. }
  563.  
  564. short
  565. LexDecimal(void)
  566. {
  567.     char *lexBuf = LFBase->lf_Buf;
  568.     long i = LFBase->lf_Index;
  569.     ubyte c = lexBuf[i++];
  570.     long v = 0;
  571.     long b = i - 1;    /*  if flt  */
  572.  
  573.     LexUnsigned = 0;
  574.     while (c >= '0' && c <= '9') {
  575.     v = (v * 10) + (c - '0');
  576.     c = lexBuf[i++];
  577.     }
  578.     if (v & 0x80000000)
  579.     LexUnsigned = 1;
  580.  
  581.     while (c == 'L' || c == 'l' || c == 'U' || c == 'u') {
  582.     if (c == 'u' || c == 'U')
  583.         LexUnsigned = 1;
  584.     c = lexBuf[i++];
  585.     }
  586.     if (c == '.' || c == 'e' || c == 'E')
  587.     return(LexFloating(b, i - 1));
  588.     LFBase->lf_Index = i - 1;
  589.     LexIntConst = v;
  590.     return(TokIntConst);
  591. }
  592.  
  593. short
  594. LexHex(ubyte c, long i)
  595. {
  596.     long v = 0;
  597.     char *lexBuf = LFBase->lf_Buf;
  598.  
  599.     for (;;) {
  600.     if (c >= '0' && c <= '9')
  601.         v = (v << 4) + (c - '0');
  602.     else if (c >= 'a' && c <= 'f')
  603.         v = (v << 4) + (c - 'a' + 10);
  604.     else if (c >= 'A' && c <= 'F')
  605.         v = (v << 4) + (c - 'A' + 10);
  606.     else
  607.         break;
  608.     c = lexBuf[i++];
  609.     }
  610.     while (c == 'L' || c == 'l' || c == 'U' || c == 'u')
  611.     c = lexBuf[i++];
  612.     LFBase->lf_Index = i - 1;
  613.     LexIntConst = v;
  614.     LexUnsigned = 1;
  615.     return(TokIntConst);
  616. }
  617.  
  618. short
  619. LexFloating(b, i)
  620. long b, i;
  621. {
  622.     char *lexBuf = LFBase->lf_Buf;
  623.     ubyte c = lexBuf[i++];
  624.  
  625.     LexStrConst = lexBuf + b;
  626.  
  627.     if (c == '.')
  628.     c = lexBuf[i++];
  629.  
  630.     while (c >= '0' && c <= '9')
  631.     c = lexBuf[i++];
  632.     if (c == 'e' || c == 'E') {     /*  En E+n E-n  */
  633.     /*
  634.      * used to set lexBuf[-1] to 'E' to fix bug in afp()
  635.      * but no longer since lexBuf may be direct from the cache!
  636.      */
  637.  
  638.     c = lexBuf[i++];
  639.     if (c == '+' || c == '-')
  640.         c = lexBuf[i++];
  641.     while (c >= '0' && c <= '9')
  642.         c = lexBuf[i++];
  643.     }
  644.  
  645.     LexStrLen = i - b - 1;
  646.     LexData = &DoubleType;
  647.  
  648.     switch(c) {
  649.     case 'f':
  650.     case 'F':
  651.     LexData = &FloatType;
  652.     ++i;
  653.     break;
  654.     case 'l':
  655.     case 'L':
  656.     LexData = &LongDoubleType;
  657.     ++i;
  658.     break;
  659.     }
  660.     LFBase->lf_Index = i - 1;
  661.  
  662.     return(TokFltConst);
  663. }
  664.  
  665. short
  666. LexCharConst(void)
  667. {
  668.     char *lexBuf = LFBase->lf_Buf;
  669.     long i = LFBase->lf_Index + 1;
  670.     ubyte c = lexBuf[i++];
  671.     short cnt = 0;
  672.     long v = 0;
  673.  
  674.     while (c != '\'') {
  675.     if (c == 0)
  676.         zerror(EFATAL_UNEXPECTED_EOF);
  677.     if (c == '\\') {
  678.         if (lexBuf[i] == '\n') {
  679.         c = lexBuf[i+1];
  680.         i += 2;
  681.         continue;
  682.         }
  683.         c = SpecialChar(&i);
  684.     }
  685.     v = (v << 8) | c;
  686.     ++cnt;
  687.     c = lexBuf[i++];
  688.     }
  689.     if (cnt > 4)
  690.     zerror(EWARN_CHAR_CONST_TOO_LONG);
  691.     if (cnt == 1)
  692.     v = (char)v;
  693.     LFBase->lf_Index = i;
  694.     LexIntConst = v;
  695.     LexUnsigned = 0;
  696.     return(TokIntConst);
  697. }
  698.  
  699. /*
  700.  *  Extract a lexical string.  Since we may be referencing out of a
  701.  *  file cache, and since we must terminate the string with \0, we
  702.  *  therefore have to make a copy.
  703.  */
  704.  
  705. short
  706. LexString(void)
  707. {
  708.     long i;
  709.     long n;
  710.     ubyte c;
  711.     ubyte nlisc = 0;
  712.     ubyte pass = 0;
  713.     char *ptr = NULL;
  714.     char *lexBuf = LFBase->lf_Buf;
  715.  
  716.     for (pass = 0; pass < 2; ++pass) {
  717.     i = LFBase->lf_Index;
  718.     n = 0;
  719.  
  720.     for (;;) {
  721.         for (++i; (c = lexBuf[i]) != '\"'; ++i) {
  722.         if (c == 0)
  723.             zerror(EFATAL_UNEXPECTED_EOF);
  724.         if (c == '\n' && nlisc == 0) {
  725.             nlisc = 1;
  726.             zerror(EWARN_NEWLINE_IN_STRING_CONST);
  727.         }
  728.         if (c == '\\') {
  729.             ++i;
  730.             if (lexBuf[i] == '\n')
  731.             continue;
  732.             c = SpecialChar(&i);
  733.             --i;
  734.         }
  735.         if (ptr)
  736.             ptr[n] = c;
  737.         ++n;
  738.         }
  739.  
  740.         /*
  741.          *    Check for concactenated strings
  742.          */
  743.  
  744.         for (c = lexBuf[++i]; TokenType[c] == TWHITE || TokenType[c] == TLF; c = lexBuf[++i])
  745.         ;
  746.         if (c != '\"')
  747.         break;
  748.     }
  749.     if (pass == 0)
  750.         ptr = zalloc(n + 1);
  751.     else
  752.         ptr[n] = 0;
  753.     ++n;
  754.     }
  755.     LFBase->lf_Index = i;
  756.     LexStrConst = ptr;
  757.     LexStrLen = n;
  758.     return(TokStrConst);
  759. }
  760.  
  761.  
  762. #ifdef NOTDEF
  763. xshort
  764. xLexString(void)
  765. x{
  766. x    long i = LexIdx + 1;
  767. x    ubyte c;
  768. x    ubyte nlisc = 0;
  769. x    long b = i;     /*  base of string frag */
  770. x    long j = i;     /*  actual write idx    */
  771. x    long appnl = 0;
  772. x
  773. x    for (;;) {
  774. x     c = LexBuf[i++];
  775. x
  776. x     while (c != '\"') {
  777. x         if (c == 0)
  778. x         zerror(EFATAL_UNEXPECTED_EOF);
  779. x         if (c == '\n' && nlisc == 0) {
  780. x         nlisc = 1;
  781. x         zerror(EWARN_NEWLINE_IN_STRING_CONST);
  782. x         }
  783. x         if (c == '\\') {
  784. x         if (LexBuf[i] == '\n') {
  785. x             c = LexBuf[i+1];
  786. x             i += 2;
  787. x             ++appnl;
  788. x             continue;
  789. x         }
  790. x         c = SpecialChar(&i);
  791. x         }
  792. x         LexBuf[j++] = c;
  793. x         c = LexBuf[i++];
  794. x     }
  795. x     /*
  796. x      *  string LexBuf + b of length (j - b).  Check for concactenated strs
  797. x      *  as per ANSI.  Track file line numbering so we can recover it
  798. x      *  later.
  799. x      */
  800. x
  801. x     c = LexBuf[i];
  802. x     while (TokenType[c] == TWHITE || TokenType[c] == TLF) {
  803. x         if (c == '\n')
  804. x         ++appnl;
  805. x         c = LexBuf[++i];
  806. x     }
  807. x     if (c != '\"')
  808. x         break;
  809. x     ++i;
  810. x    }
  811. x
  812. x    /*
  813. x     *  Terminating \0 is implicit to string constants, e.g. sizeof("abc").
  814. x     *  Note that this also serves as a start-string indication for the
  815. x     *  error routines (to avoid embedded newlines)
  816. x     */
  817. x
  818. x    LexBuf[j++] = 0;
  819. x    LexIdx = i;
  820. x    LexStrConst = (char *)LexBuf + b;
  821. x    LexStrLen     = j - b;
  822. x
  823. x    /*
  824. x     *  Clear out extra junk
  825. x     */
  826. x
  827. x    while (j + appnl < i)
  828. x     LexBuf[j++] = ' ';
  829. x
  830. x    /*
  831. x     *  Mark area as munged
  832. x     */
  833. x
  834. x    MarkAreaMunged(b, j);
  835. x
  836. x    /*
  837. x     *  Recover dummy newlines that were embedded in the string so line
  838. x     *  number tracking doesn't screw up
  839. x     */
  840. x
  841. x    while (appnl--)
  842. x     LexBuf[j++] = '\n';
  843. x
  844. x    return(TokStrConst);
  845. x}
  846. #endif
  847.  
  848. /*
  849.  *  LexSimpleToken() returns simple tokens such as +, ++, etc..
  850.  */
  851.  
  852. short
  853. LexSimpleToken(void)
  854. {
  855.     ubyte *ptr = LFBase->lf_Buf + LFBase->lf_Index + 1;
  856.     short token;
  857.  
  858.     switch(ptr[-1]) {
  859.     case '!':   /*  !, !=   */
  860.     if (*ptr == '=') {
  861.         token = TokNotEq;
  862.         ++ptr;
  863.         break;
  864.     }
  865.     token = TokNot;
  866.     break;
  867.     case '%':   /*  %, %=   */
  868.     if (*ptr == '=') {
  869.         token = TokPercentEq;
  870.         ++ptr;
  871.         break;
  872.     }
  873.     token = TokPercent;
  874.     break;
  875.     case '&':   /*  &, &&, &=   */
  876.     if (*ptr == '&') {
  877.         token = TokAndAnd;
  878.         ++ptr;
  879.         break;
  880.     }
  881.     if (*ptr == '=') {
  882.         token = TokAndEq;
  883.         ++ptr;
  884.         break;
  885.     }
  886.     token = TokAnd;
  887.     break;
  888.     case '(':
  889.     token = TokLParen;
  890.     break;
  891.     case ')':
  892.     token = TokRParen;
  893.     break;
  894.     case '*':   /*  *, *=   */
  895.     if (*ptr == '=') {
  896.         token = TokStarEq;
  897.         ++ptr;
  898.         break;
  899.     }
  900.     token = TokStar;
  901.     break;
  902.     case '+':   /*  +, ++, +=   */
  903.     if (*ptr == '+') {
  904.         token = TokPlPl;
  905.         ++ptr;
  906.         break;
  907.     }
  908.     if (*ptr == '=') {
  909.         token = TokPlEq;
  910.         ++ptr;
  911.         break;
  912.     }
  913.     token = TokPl;
  914.     break;
  915.     case ',':
  916.     token = TokComma;
  917.     break;
  918.     case '-':   /*  -, --, -=, ->   */
  919.     switch(*ptr) {
  920.     case '-':
  921.         token = TokMiMi;
  922.         ++ptr;
  923.         break;
  924.     case '=':
  925.         token = TokMiEq;
  926.         ++ptr;
  927.         break;
  928.     case '>':
  929.         token = TokStrInd;
  930.         ++ptr;
  931.         break;
  932.     default:
  933.         token = TokMi;
  934.         break;
  935.     }
  936.     break;
  937.     case '.':
  938.     if (*ptr >= '0' && *ptr <= '9') {
  939.         long i = (char *)ptr - (char *)LFBase->lf_Buf - 1;
  940.         return(LexFloating(i, i));
  941.     }
  942.     if (*ptr == '.' && ptr[1] == '.') {
  943.         token = TokDotDotDot;
  944.         ptr += 2;
  945.         break;
  946.     }
  947.     token = TokStrElm;
  948.     break;
  949.     case '/':   /*  /, /=   */
  950.     if (*ptr == '=') {
  951.         token = TokDivEq;
  952.         ++ptr;
  953.         break;
  954.     }
  955.     token = TokDiv;
  956.     break;
  957.     case '<':   /*  <, <<, <<=, <=  */
  958.     if (*ptr == '<') {
  959.         if (ptr[1] == '=') {
  960.         token = TokLtLtEq;
  961.         ptr += 2;
  962.         break;
  963.         }
  964.         token = TokLtLt;
  965.         ++ptr;
  966.         break;
  967.     }
  968.     if (*ptr == '=') {
  969.         token = TokLtEq;
  970.         ++ptr;
  971.         break;
  972.     }
  973.     token = TokLt;
  974.     break;
  975.     case '=':
  976.     if (*ptr == '=') {
  977.         token = TokEqEq;
  978.         ++ptr;
  979.         break;
  980.     }
  981.     token = TokEq;
  982.     break;
  983.     case '>':
  984.     if (*ptr == '>') {
  985.         if (ptr[1] == '=') {
  986.         token = TokGtGtEq;
  987.         ptr += 2;
  988.         break;
  989.         }
  990.         token = TokGtGt;
  991.         ++ptr;
  992.         break;
  993.     }
  994.     if (*ptr == '=') {
  995.         token = TokGtEq;
  996.         ++ptr;
  997.         break;
  998.     }
  999.     token = TokGt;
  1000.     break;
  1001.     case '?':
  1002.     token = TokQuestion;
  1003.     break;
  1004.     case ':':
  1005.     token = TokColon;
  1006.     break;
  1007.     case '[':
  1008.     token = TokLBracket;
  1009.     break;
  1010.     case ']':
  1011.     token = TokRBracket;
  1012.     break;
  1013.     case '^':
  1014.     if (*ptr == '=') {
  1015.         token = TokCaratEq;
  1016.         ++ptr;
  1017.         break;
  1018.     }
  1019.     token = TokCarat;
  1020.     break;
  1021.     case '|':
  1022.     if (*ptr == '|') {
  1023.         token = TokOrOr;
  1024.         ++ptr;
  1025.         break;
  1026.     }
  1027.     if (*ptr == '=') {
  1028.         token = TokOrEq;
  1029.         ++ptr;
  1030.         break;
  1031.     }
  1032.     token = TokOr;
  1033.     break;
  1034.     case '~':
  1035.     token = TokTilde;
  1036.     break;
  1037.     case '{':
  1038.     token = TokLBrace;
  1039.     break;
  1040.     case '}':
  1041.     token = TokRBrace;
  1042.     break;
  1043.     case ';':
  1044.     token = TokSemi;
  1045.     break;
  1046.     case 0:    /*  force table lookup for critical code */
  1047.     if (PopLexFile()) {
  1048.         return(GetToken());
  1049.     }
  1050.     /*
  1051.      *  Do not update LexIdx
  1052.      */
  1053.     return(0);
  1054.     case '#':   /*  hack to handle # directive on line 1   */
  1055.     if (LFBase->lf_Index == 0)
  1056.         return(LexLineFeed());
  1057.     /* fall through */
  1058.     case 1:
  1059.     case 2:
  1060.     case 3:
  1061.     case 4:
  1062.     case 5:
  1063.     case 6:
  1064.     case 7:
  1065.     case 8:
  1066.     case 9:
  1067.     case 10:
  1068.     case 11:
  1069.     case 12:
  1070.     case 13:
  1071.     case 14:
  1072.     case 15:
  1073.     case 16:
  1074.     case 17:
  1075.     case 18:
  1076.     case 19:
  1077.     case 20:
  1078.     case 21:
  1079.     case 22:
  1080.     case 23:
  1081.     case 24:
  1082.     case 25:
  1083.     case 26:
  1084.     case 27:
  1085.     case 28:
  1086.     case 29:
  1087.     case 30:
  1088.     case 31:
  1089.     case 'a':
  1090.     case 'b':
  1091.     case 'c':
  1092.     case 'd':
  1093.     case 'e':
  1094.     case 'f':
  1095.     case 'g':
  1096.     case 'h':
  1097.     case 'i':
  1098.     case 'j':
  1099.     case 'k':
  1100.     case 'l':
  1101.     case 'm':
  1102.     case 'n':
  1103.     case 'o':
  1104.     case 'p':
  1105.     case 'q':
  1106.     case 'r':
  1107.     case 's':
  1108.     case 't':
  1109.     case 'u':
  1110.     case 'v':
  1111.     case 'w':
  1112.     case 'x':
  1113.     case 'y':
  1114.     case 'z':
  1115.     case 'A':
  1116.     case 'B':
  1117.     case 'C':
  1118.     case 'D':
  1119.     case 'E':
  1120.     case 'F':
  1121.     case 'G':
  1122.     case 'H':
  1123.     case 'I':
  1124.     case 'J':
  1125.     case 'K':
  1126.     case 'L':
  1127.     case 'M':
  1128.     case 'N':
  1129.     case 'O':
  1130.     case 'P':
  1131.     case 'Q':
  1132.     case 'R':
  1133.     case 'S':
  1134.     case 'T':
  1135.     case 'U':
  1136.     case 'V':
  1137.     case 'W':
  1138.     case 'X':
  1139.     case 'Y':
  1140.     case 'Z':
  1141.     default:
  1142.     zerror(EWARN_ILLEGAL_CHAR, ptr[-1], ptr[-1]);
  1143.     token = TokSemi;
  1144.     break;
  1145.     }
  1146.     LFBase->lf_Index = (char *)ptr - (char *)LFBase->lf_Buf;
  1147.     return(token);
  1148. }
  1149.  
  1150. /*
  1151.  *  MISC
  1152.  *
  1153.  */
  1154.  
  1155. int
  1156. SpecialChar(pi)
  1157. long *pi;
  1158. {
  1159.     long i = *pi;
  1160.     int c = LFBase->lf_Buf[i];
  1161.     int v = 0;
  1162.  
  1163.     *pi = ++i;
  1164.  
  1165.     switch(c) {
  1166.     case 10:    /*  a newline!    */
  1167.     c = LFBase->lf_Buf[i];
  1168.     *pi = ++i;
  1169.     return(c);
  1170.     break;
  1171.     case 'n':
  1172.     return(10);
  1173.     case 'r':
  1174.     return(13);
  1175.     case 't':
  1176.     return(9);
  1177.     case 'f':
  1178.     return(12);
  1179.     case 'v':
  1180.     return(11);
  1181.     case 'a':
  1182.     return(7);
  1183.     case 'b':
  1184.     return(8);
  1185.     case 'x':
  1186.         for(;;)
  1187.         {
  1188.         c = LFBase->lf_Buf[i];
  1189.         switch(TokenType[c])
  1190.         {
  1191.         case TALPHX:
  1192.             c = (c & 7) + 9;    /* The & 7 makes the Upper and lower case */
  1193.                     /* characters appear the same             */
  1194.             break;
  1195.         case TNUM:
  1196.         case TZERO:
  1197.             c -= '0';
  1198.             break;
  1199.         default:
  1200.                     if ((i - *pi) > 2)
  1201.                     {
  1202.                        zerror(EWARN_HEX_CONST_TRUNCATED);
  1203.                     }
  1204.             *pi = i;
  1205.             return(v);
  1206.         }
  1207.             i++;
  1208.             v <<= 4;
  1209.             v += c;
  1210.     }
  1211.     default:
  1212.         {
  1213.            int cnt = 0;
  1214.  
  1215.            while ((cnt < 3) && (c >= '0') && (c <= '7'))
  1216.            {
  1217.               v = (v << 3) | (c - '0');
  1218.               c = LFBase->lf_Buf[i];
  1219.               i++;
  1220.               cnt++;
  1221.            }
  1222.            if (cnt)
  1223.               i--;
  1224.            else
  1225.               v = c;
  1226.            *pi = i;
  1227.            return(v);
  1228.         }
  1229.     }
  1230. }
  1231.  
  1232. long
  1233. CharToNibble(short c)
  1234. {
  1235.     if (c >= '0' && c <= '9')
  1236.     return(c - '0');
  1237.     return((c | 0x20) - 'a' + 10);
  1238. }
  1239.  
  1240. short
  1241. SkipToken(short t, short expect)
  1242. {
  1243.     if (t == expect)
  1244.     return(GetToken());
  1245.     zerror(EERROR_UNEXPECTED_TOKEN, TokenToStr(t), TokenToStr(expect));
  1246.     return(t);
  1247. }
  1248.  
  1249. char *
  1250. TokenToStr(short t)
  1251. {
  1252.     switch(t) {
  1253.     case TokComma:
  1254.     return(",");
  1255.     case TokSemi:
  1256.     return(";");
  1257.     case TokLParen:
  1258.     return("(");
  1259.     case TokRParen:
  1260.     return(")");
  1261.     case TokLBrace:
  1262.     return("{");
  1263.     case TokRBrace:
  1264.     return("}");
  1265.     case TokColon:
  1266.     return(":");
  1267.     case TokLBracket:
  1268.     return("[");
  1269.     case TokRBracket:
  1270.     return("]");
  1271.     default:
  1272.     return("<unknown>");
  1273.     }
  1274. }
  1275.  
  1276. /*
  1277.  *  Find the line number associated with a lexical offset
  1278.  */
  1279.  
  1280. long
  1281. FindLexFileLine(lexIdx, plexFile, plexFileNameLen, plexIdxBeg)
  1282. long lexIdx;
  1283. char **plexFile;
  1284. long *plexFileNameLen;
  1285. long *plexIdxBeg;
  1286. {
  1287.     long i;
  1288.     char *ptr;
  1289.     long lexLine = -1;
  1290.  
  1291.     static long CacheLexIdx = -1;
  1292.     static long CacheLexLine;
  1293.     static char *CacheLexFile;
  1294.     static long CacheLexFileNameLen;
  1295.  
  1296.  
  1297.     /*
  1298.      *    find start of line
  1299.      */
  1300.  
  1301.     *plexIdxBeg = lexIdx;
  1302.     *plexFile = "";
  1303.  
  1304.     if (LFBase == NULL)
  1305.     return(0);
  1306.  
  1307.     for (i = lexIdx, ptr = LFBase->lf_Buf + i; i > 0; --i) {
  1308.     if (ptr[-1] == '\n' /*&& !OffsetMunged(i-1)*/) {
  1309.         *plexIdxBeg = i;
  1310.         break;
  1311.     }
  1312.     --ptr;
  1313.     }
  1314.     /*printf(";i %d/%d:%c\n", i, LFBase->lf_Buf[i], LFBase->lf_Buf[i]);*/
  1315.  
  1316.     if (i == CacheLexIdx) {
  1317.     *plexFile    = CacheLexFile;
  1318.     *plexFileNameLen= CacheLexFileNameLen;
  1319.     *plexIdxBeg    = i;
  1320.     return(CacheLexLine);
  1321.     }
  1322.  
  1323.     /*
  1324.      *    reverse scan for '# <line> "<file>"'
  1325.      */
  1326.  
  1327.     while (i >= 0) {
  1328.     if (i == CacheLexIdx) {
  1329.         *plexFile = CacheLexFile;
  1330.         *plexFileNameLen = CacheLexFileNameLen;
  1331.         lexLine += CacheLexLine + 1;
  1332.         ++LexCacheHits;
  1333.         break;
  1334.     }
  1335.     if (*ptr == '#' && (i == 0 || (ptr[-1] == '\n' /*&& !OffsetMunged(i)*/))) {
  1336.         short j;
  1337.         char c;
  1338.  
  1339.         for (j = 1; (c = ptr[j]) == ' ' || c == '\t'; ++j)
  1340.         ;
  1341.         if ((c >= '0' && c <= '9') || c == '-') {
  1342.         lexLine += atoi(ptr + j);
  1343.         while ((c = ptr[j]) && c != '\"')
  1344.             ++j;
  1345.         *plexFile = ptr + j + 1;
  1346.         *plexFileNameLen = strchr(*plexFile, '\"') - *plexFile;
  1347.         if (*plexFileNameLen < 0)
  1348.             *plexFileNameLen = 0;
  1349.         CacheLexFile = *plexFile;
  1350.         CacheLexFileNameLen = *plexFileNameLen;
  1351.         ++LexCacheMisses;
  1352.         break;
  1353.  
  1354.         }
  1355.     }
  1356.     if (*ptr == '\n'/* && !OffsetMunged(i)*/)
  1357.         ++lexLine;
  1358.     --i;
  1359.     --ptr;
  1360.     }
  1361.     CacheLexLine = lexLine;
  1362.     CacheLexIdx = *plexIdxBeg;
  1363.  
  1364.     return(lexLine);
  1365. }
  1366.  
  1367. short
  1368. FindLexCharAt(i)
  1369. long i;
  1370. {
  1371.     if (LFBase) {
  1372.         if (ftell(LFBase->lf_Fi) != i)
  1373.         fseek(LFBase->lf_Fi, i, 0);
  1374.     return(getc(LFBase->lf_Fi));
  1375.     }
  1376.     return(EOF);
  1377. }
  1378.  
  1379.